package com.zzw.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.zzw.bean.Msg;
import com.zzw.bean.SysUser;
import com.zzw.service.RedisCacheService;
import com.zzw.service.SysUserService;
import com.zzw.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 系统用户管理控制器
 * @author 赵志伟
 * @version 1.0
 */
@SuppressWarnings({"all"})
@Controller
@RequestMapping("/sysUser")
@Api(tags = "系统用户管理接口")
public class SysUserController {

    // Redis键前缀
    private static final String LOGIN_FAIL_COUNT_PREFIX = "login_fail:";
    private static final String LOGIN_USER_PREFIX = "login_user:";
    private static final String EMAIL_CODE_PREFIX = "email_code:";

    // 登录失败最大次数
    private static final int MAX_FAIL_COUNT = 5;

    // 登录失败锁定时间（秒）
    private static final int LOCK_TIME = 1800;

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private Producer kaptchaProducer;
    @Autowired
    private RedisCacheService redisCacheService;

    @Value("${avatar.upload.path}")
    private String avatarUploadPath;

    @ApiOperation(value = "用户列表页面", notes = "跳转到用户列表页面")
    @RequestMapping("list")
    public String list() {
        return "sysuser/list";
    }

    @ApiOperation(value = "用户列表数据", notes = "根据条件查询用户列表数据")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "pageNum", value = "当前页码", required = false, dataType = "Integer", paramType = "query", defaultValue = "1"),
        @ApiImplicitParam(name = "pageSize", value = "每页记录数", required = false, dataType = "Integer", paramType = "query", defaultValue = "10"),
        @ApiImplicitParam(name = "sort", value = "排序字段", required = false, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "order", value = "排序方式", required = false, dataType = "String", paramType = "query")
    })
    @RequestMapping("/listByCondition")
    @ResponseBody
    public Msg listByCondition(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                               @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
                               @RequestParam(value = "sort", defaultValue = "") String sort,
                               @RequestParam(value = "order", defaultValue = "") String order,
                               SysUser sysUser) {

        PageHelper.startPage(pageNum, pageSize, WebUtils.getOrderBy(sort, order));

        List<SysUser> sysUseres = sysUserService.listByCondition(sysUser);
        PageInfo pageInfo = new PageInfo(sysUseres, pageSize);

        return Msg.success().add("pageInfo", pageInfo); //分页数据
    }

    /**
     * 处理登录请求
     */
    @ApiOperation(value = "用户登录", notes = "处理用户登录请求")
    @ResponseBody
    @PostMapping("/login")
    public Msg login(@RequestBody SysUser sysUser) {
        try {
            // 检查请求参数
            if (sysUser == null || sysUser.getUsername() == null || sysUser.getPassword() == null) {
                return Msg.fail().setMsg("用户名和密码不能为空");
            }

            String username = sysUser.getUsername();

            // 检查账号是否被锁定（登录失败次数过多）
            String lockKey = LOGIN_FAIL_COUNT_PREFIX + username;
            Integer failCount = (Integer) redisCacheService.getCache(lockKey);

            if (failCount != null && failCount >= MAX_FAIL_COUNT) {
                return Msg.fail().setMsg("账号已被锁定，请" + LOCK_TIME/60 + "分钟后再试");
            }

            // 获取当前主体
            Subject subject = SecurityUtils.getSubject();

            // 创建用户名密码令牌，使用明文密码
            UsernamePasswordToken token = new UsernamePasswordToken(
                    username,
                    sysUser.getPassword()
            );

            // 记住我（可选）
            token.setRememberMe(sysUser.getRememberMe());

            // 执行登录
            subject.login(token);

            // 获取用户对象
            SysUser user = (SysUser) subject.getPrincipal();

            // 将用户信息存入session
            Session session = subject.getSession();
            session.setAttribute("userId", user.getId());
            session.setAttribute("user", user);

            // 登录成功，清除失败计数
            if (failCount != null) {
                redisCacheService.deleteCache(lockKey);
            }

            // 将用户信息存入Redis，有效期与会话相同
            String userKey = LOGIN_USER_PREFIX + user.getId();
            redisCacheService.setCache(userKey, user, session.getTimeout() / 1000); // 转换为秒

            return Msg.success().add("user", user).setMsg("登录成功");
        } catch (UnknownAccountException e) {
            return Msg.fail().setMsg("账户不存在");
        } catch (DisabledAccountException e) {
            return Msg.fail().setMsg("账户已被禁用");
        } catch (AuthenticationException e) {
            // 登录失败，增加失败计数
            String lockKey = LOGIN_FAIL_COUNT_PREFIX + sysUser.getUsername();
            Integer failCount = (Integer) redisCacheService.getCache(lockKey);

            if (failCount == null) {
                failCount = 1;
            } else {
                failCount += 1;
            }

            // 设置失败计数，过期时间为锁定时间
            redisCacheService.setCache(lockKey, failCount, LOCK_TIME);

            // 如果达到最大失败次数，提示账号被锁定
            if (failCount >= MAX_FAIL_COUNT) {
                return Msg.fail().setMsg("账号已被锁定，请" + LOCK_TIME/60 + "分钟后再试");
            }

            return Msg.fail().setMsg("用户名或密码错误，还有" + (MAX_FAIL_COUNT - failCount) + "次机会");
        } catch (Exception e) {
            e.printStackTrace();
            return Msg.fail().setMsg("登录失败：" + e.getMessage());
        }
    }

    //注册
    @ApiOperation(value = "用户注册", notes = "处理用户注册请求")
    @RequestMapping("/register")
    @ResponseBody
    public Msg register(@RequestBody SysUser sysUser, HttpSession session) {
        Map<String, Object> params = sysUser.getParams();

        // 检查是否有邮箱验证码参数
        if (params != null && params.containsKey("email") && params.containsKey("emailCode")) {
            String email = (String) params.get("email");
            String emailCode = (String) params.get("emailCode");

            // 验证邮箱验证码
            String emailCodeKey = EMAIL_CODE_PREFIX + email;
            String storedCode = (String) redisCacheService.getCache(emailCodeKey);

            if (storedCode == null || !storedCode.equals(emailCode)) {
                return Msg.fail().setMsg("邮箱验证码错误或已过期");
            }

            // 验证通过，删除验证码
            redisCacheService.deleteCache(emailCodeKey);
        } else {
            // 检查图形验证码
            String kaptcha = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
            // 清除session验证码
            session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);

            String code = params != null ? (String) params.get("code") : null;
            if (code == null || !code.equalsIgnoreCase(kaptcha)) {
                return Msg.fail().setMsg("验证码错误");
            }
        }

        return sysUserService.register(sysUser);
    }

    //新增
    @ApiOperation(value = "添加用户", notes = "添加新用户")
    @ApiImplicitParam(name = "file", value = "用户头像文件", required = false, dataType = "MultipartFile", paramType = "form")
    @RequestMapping("/add")
    @ResponseBody
    public Msg add(SysUser sysUser, @RequestParam("file") MultipartFile file) {
        return sysUserService.add(sysUser, file);
    }

    //删除
    @ApiOperation(value = "删除用户", notes = "根据ID删除用户")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Integer", paramType = "query")
    @RequestMapping("/delete")
    @ResponseBody
    public Msg delete(Integer id) {
        Msg msg = Msg.success();

        boolean delete = sysUserService.delete(id);
        if (delete) {
            msg.setMsg("删除成功");
        } else {
            msg.setMsg("删除失败");
        }
        return msg;
    }

    //修改
    @ApiOperation(value = "更新用户信息", notes = "修改用户信息")
    @RequestMapping("/update")
    @ResponseBody
    public Msg update(@RequestBody SysUser sysUser) {
        boolean update = sysUserService.update(sysUser);
        if (update) {
            return Msg.success();
        } else {
            return Msg.fail();
        }
    }

    @ApiOperation(value = "获取当前用户信息", notes = "根据用户ID获取当前用户信息")
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "Integer", paramType = "query")
    @GetMapping("/getCurrentUser")
    @ResponseBody
    public Msg getCurrentUser(@RequestParam("userId") Integer userId) {
        // 先从Redis缓存获取用户信息
        String userKey = LOGIN_USER_PREFIX + userId;
        SysUser currentUser = (SysUser) redisCacheService.getCache(userKey);

        // 如果缓存中没有，则从数据库查询
        if (currentUser == null) {
            currentUser = sysUserService.getCurrentUser(userId);

            // 如果数据库中有此用户，则缓存用户信息
            if (currentUser != null) {
                Subject subject = SecurityUtils.getSubject();
                if (subject.isAuthenticated()) {
                    // 用户已登录，缓存用户信息
                    Session session = subject.getSession();
                    redisCacheService.setCache(userKey, currentUser, session.getTimeout() / 1000);
                }
            }
        }

        if (currentUser != null) {
            return Msg.success().add("user", currentUser);
        } else {
            return Msg.fail();
        }
    }

    /**
     * 获取当前用户的权限列表
     * 用于前端权限控制
     */
    @ApiOperation(value = "获取用户权限列表", notes = "获取当前用户的权限列表，用于前端权限控制")
    @GetMapping("/getUserPermissions")
    @ResponseBody
    public Msg getUserPermissions() {
        try {
            // 获取当前登录的用户
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isAuthenticated()) {
                return Msg.fail().setMsg("用户未登录");
            }

            // 从Subject中获取用户对象
            SysUser user = (SysUser) subject.getPrincipal();
            if (user == null) {
                return Msg.fail().setMsg("获取用户信息失败");
            }

            // 调用Service获取用户权限
            List<String> permissions = sysUserService.getUserPermissions(user.getId());

            return Msg.success().add("permissions", permissions);
        } catch (Exception e) {
            e.printStackTrace();
            return Msg.fail().setMsg("获取权限列表失败：" + e.getMessage());
        }
    }

    @PostMapping("/uploadAvatar")
    @ResponseBody
    public Msg uploadAvatar(@RequestParam("avatar") MultipartFile file, HttpSession session) {
        try {
            // 获取当前用户ID
            Integer userId = (Integer) session.getAttribute("userId");
            if (userId == null) {
                return Msg.fail("用户未登录");
            }

            // 生成唯一文件名
            String originalName = file.getOriginalFilename();
            String suffix = originalName.substring(originalName.lastIndexOf("."));
            String fileName = UUID.randomUUID() + suffix;

            // 删除旧头像
            deleteOldAvatar(userId);

            // 处理OSS路径并上传
            String ossPath = OssUtil.formatOssPath(avatarUploadPath);
            String finalObjectName = ossPath + fileName;
            String avatarUrl = OssUtil.uploadMultipartFile(file, finalObjectName);

            // 更新用户头像URL
            boolean updated = sysUserService.updateAvatar(userId, avatarUrl);

            // 更新Redis缓存
            if (updated) {
                updateUserCache(userId);
                return Msg.success().add("avatarUrl", avatarUrl);
            } else {
                return Msg.fail("更新头像失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Msg.fail("文件上传失败：" + e.getMessage());
        }
    }

    /**
     * 删除用户旧头像
     */
    private void deleteOldAvatar(Integer userId) {
        try {
            SysUser user = sysUserService.getCurrentUser(userId);
            if (user.getAvatar() != null && user.getAvatar().contains("/")) {
                String objectName = user.getAvatar().substring(user.getAvatar().lastIndexOf("/") + 1);
                String ossPath = OssUtil.formatOssPath(avatarUploadPath);
                OssUtil.delete(ossPath + objectName);
            }
        } catch (Exception e) {
            // 旧头像删除失败不影响上传新头像
            System.out.println("旧头像删除失败: " + e.getMessage());
        }
    }

    /**
     * 更新用户缓存信息
     */
    private void updateUserCache(Integer userId) {
        SysUser user = sysUserService.getCurrentUser(userId);
        redisCacheService.deleteCache(LOGIN_USER_PREFIX + userId);
        redisCacheService.setCache(LOGIN_USER_PREFIX + userId, user,
                ShiroUtils.getSession().getTimeout() / 1000);
    }

    @PostMapping("/updateUserInfo")
    @ResponseBody
    public Msg updateUserInfo(@RequestBody SysUser sysUser, HttpSession session) {
        // 获取当前登录用户ID
        Integer userId = (Integer) session.getAttribute("userId");
        if (userId == null) {
            return Msg.fail("用户未登录");
        }

        // 确保只能修改当前登录用户的信息
        sysUser.setId(userId);

        // 更新用户信息
        boolean updated = sysUserService.updateUserInfo(sysUser);
        if (updated) {
            return Msg.success().setMsg("个人信息更新成功");
        } else {
            return Msg.fail("更新失败");
        }
    }

    @PostMapping("/changePassword")
    @ResponseBody
    public Msg changePassword(@RequestBody Map<String, String> passwordMap,
                              HttpSession session) {
        // 获取当前登录用户ID
        Integer userId = (Integer) session.getAttribute("userId");
        if (userId == null) {
            return Msg.fail("用户未登录");
        }

        String oldPassword = passwordMap.get("oldPassword");
        String newPassword = passwordMap.get("newPassword");

        if (oldPassword == null || newPassword == null) {
            return Msg.fail("密码不能为空");
        }

        // 调用Service层方法修改密码
        boolean updated = sysUserService.changePassword(userId, oldPassword, newPassword);
        if (updated) {
            return Msg.success().setMsg("密码修改成功");
        } else {
            return Msg.fail("原密码错误或修改失败");
        }
    }

    /**
     * 处理注销请求
     */
    @ResponseBody
    @GetMapping("/logout")
    public Msg logout() {
        try {
            // 获取当前主体并注销
            Subject subject = SecurityUtils.getSubject();
            if (subject.isAuthenticated()) {
                // 获取用户信息
                SysUser user = (SysUser) subject.getPrincipal();

                // 清除Redis缓存
                if (user != null) {
                    // 清除用户信息缓存
                    redisCacheService.deleteCache(LOGIN_USER_PREFIX + user.getId());

                    // 清除登录失败次 数缓存
                    redisCacheService.deleteCache(LOGIN_FAIL_COUNT_PREFIX + user.getUsername());

                    // 清除会话相关缓存
                    String sessionId = subject.getSession().getId().toString();
                    redisCacheService.deleteCache("shiro:session:" + sessionId);
                }

                // 停止会话
                //...

                // 执行登出
                subject.logout();
            }
            return Msg.success().setMsg("注销成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Msg.fail().setMsg("注销失败：" + e.getMessage());
        }
    }

    @RequestMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置响应头
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");

        // 生成验证码
        String capText = kaptchaProducer.createText();
        // 将验证码存储在session中
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_DATE, new Date());

        BufferedImage image = kaptchaProducer.createImage(capText);
        ServletOutputStream outputStream = response.getOutputStream();

        // 将验证码图片输出到响应流
        ImageIO.write(image, "jpg", outputStream);
    }

    /**
     * 发送手机验证码
     * @Param mobilePhone 手机号码
     * @return 验证码
     */
    @RequestMapping("/sendSms")
    public Msg sendSms(String mobilePhone) {
        //调用短信服务发送验证码


        return Msg.success();
    }
}
